<!-- 1 -->
<template>
    <div class="g6-wrapper">
        <div class="ai-container"></div>
    </div>
</template>

<script>
import G6 from '@antv/g6';
import data from './datas/demo1';

const testData = {
    // 点集
    nodes: [
        {
            id: 'node1',
            label: 'node1',
            x: 100,
            y: 200,
            linkPoints: {
                top: [{ id: '1' }, { id: '2' }],
            },
            visible: true,
            type: 'circle-animate',
        },
        {
            id: 'node2',
            label: 'node2',
            x: 400,
            y: 200,
        },
    ],
    // 边集
    edges: [
        // 表示一条从 node1 节点连接到 node2 节点的边
        {
            source: 'node1',
            target: 'node2',
            style: {
                stroke: 'blue',
            },
        },
    ],
};

export default {
    inheritAttrs: false,
    props: {},
    data() {
        return {};
    },
    components: {},
    computed: {},
    created() {},
    mounted() {
        this.initGraph();
    },
    methods: {
        initGraph() {
            const designerBox = this.$el.querySelector('.ai-container');
            const designerRect = designerBox?.getBoundingClientRect();

            const grid = new G6.Grid();
            /**
             * minimap 原理是将主画布内容复制到 minimap 的画布, 在大数据量下可能会造成双倍的绘制效率成本。
             * 为缓解该问题, image minimap 采用图片地址或者 base64字符串 graphImg 绘制 <img /> 代替 minimap,
             * 但 graphImg 完全交由用户自己控制。
             */
            // const minimap = new G6.Minimap({
            //     size: [100, 100],
            //     className: 'minimap',
            //     type: 'delegate',
            // });

            const imageMinimap = new G6.ImageMinimap({
                width: 200,
                graphImg: 'https://gw.alipayobjects.com/mdn/rms_f8c6a0/afts/img/A*eD7nT6tmYgAAAAAAAAAAAABkARQnAQ',
            });
            this.flowGraph = new G6.Graph({
                plugins: [grid, imageMinimap],
                container: designerBox,
                width: designerRect?.width ?? 800,
                height: designerRect?.height ?? 500,

                defaultEdge: {
                    type: 'circle',
                },
                defaultNode: {
                    // type: 'modelRect',
                    anchorPoints: [
                        [0, 0.5],
                        [1, 0.5],
                        [0.5, 0],
                        [0.5, 1],
                    ],
                },
                nodeStateStyles: {
                    // active: {
                    //     stroke: 'red',
                    // },
                    // hover: {
                    //     fill: 'lightsteelblue',
                    // },
                },
                modes: {
                    default: [
                        'drag-canvas',
                        'zoom-canvas',
                        'drag-node',
                        'drag-combo',
                        'activate-node',
                        {
                            type: 'tooltip', // 提示框
                            formatText(model) {
                                // 提示框文本内容
                                const text = 'label: ' + model.label + '<br/> class: ' + model.class;
                                return text;
                            },
                        },
                    ],
                },
                //fitView: true, // 设置是否将图适配到画布中
                //fitViewPadding: 10, //画布上四周的留白宽度
                animate: true,
                layout: {
                    // Object，可选，布局的方法及其配置项，默认为 random 布局。
                    type: 'force', // 指定为力导向布局
                    preventOverlap: true, // 防止节点重叠
                    nodeSize: 30, // 节点大小，用于算法中防止节点重叠时的碰撞检测。由于已经在上一节的元素配置中设置了每个节点的 size 属性，则不需要在此设置 nodeSize。
                    linkDistance: 100, // 指定边距离
                },
            });
            this.registerBehavior();
            this.flowGraph.setMode('default');
            this.renderGraph();

            const img = require('@/assets/img.jpg');
            imageMinimap.updateGraphImg(img);
        },
        registerBehavior() {
            ///鼠标进入节点;
            this.flowGraph.on('node:mouseenter', (e) => {
                const nodeItem = e.item; // 获取鼠标进入的节点元素对象
                this.flowGraph.setItemState(nodeItem, 'hover', true); // 设置当前节点的 hover 状态为 true
            });

            // 鼠标离开节点
            this.flowGraph.on('node:mouseleave', (e) => {
                const nodeItem = e.item; // 获取鼠标离开的节点元素对象
                this.flowGraph.setItemState(nodeItem, 'hover', false); // 设置当前节点的 hover 状态为 false
            });

            /**
             * 自定义交互行为
             * 自定义的交互行为需要在实例之前创建 或者再次 setMode
             *
             */
            G6.registerBehavior('activate-node', {
                getDefaultCfg() {
                    return {
                        multiple: true,
                    };
                },
                getEvents() {
                    return {
                        'node:click': 'onNodeClick',
                        'canvas:click': 'onCanvasClick',
                    };
                },
                onNodeClick(e) {
                    const item = e.item;
                    if (item.hasState('active')) {
                        this.graph.setItemState(item, 'active', false);
                        return;
                    }
                    // this 上即可取到配置，如果不允许多个 'active'，先取消其他节点的 'active' 状态
                    if (!this.multiple) {
                        this.removeNodesState();
                    }
                    // 置点击的节点状态 'active' 为 true
                    this.graph.setItemState(item, 'active', true);
                },

                onCanvasClick(e) {
                    // shouldUpdate 可以由用户复写，返回 true 时取消所有节点的 'active' 状态，即将 'active' 状态置为 false
                    if (this.shouldUpdate(e)) {
                        this.removeNodesState();
                    }
                },
                removeNodesState() {
                    this.graph.findAllByState('node', 'active').forEach((node) => {
                        this.graph.setItemState(node, 'active', false);
                    });
                },
            });

            // Scale Animation
            G6.registerNode(
                'circle-animate',
                {
                    afterDraw(cfg, group) {
                        const shape = group.get('children')[0];
                        shape.animate(
                            (ratio) => {
                                const diff = ratio <= 0.5 ? ratio * 10 : (1 - ratio) * 10;
                                return {
                                    r: cfg.size / 2 + diff,
                                };
                            },
                            {
                                repeat: true,
                                duration: 3000,
                                easing: 'easeCubic',
                            }
                        );
                    },
                },
                'circle'
            );
        },
        /**
         * 数据为 g6 文档案例数据
         * fetch api : https://developer.mozilla.org/zh-CN/docs/Web/API/Fetch_API
         */
        async renderGraph() {
            const response = await fetch('https://gw.alipayobjects.com/os/basement_prod/6cae02ab-4c29-44b2-b1fd-4005688febcb.json');
            const remoteData = await response.json();
            console.error(remoteData, '远程数据');
            // this.flowGraph.changeData(data);
            this.flowGraph.data(testData);
            // this.flowGraph.data(remoteData);
            this.flowGraph.render();
        },
    },
};
</script>
<style lang="scss" scoped>
.g6-wrapper {
    position: relative;
    .ai-container {
        width: 100%;
        height: 100%;
        border: 1px solid #ccc;
        user-select: none;

        // 缩略图
        ::v-deep.minimap,
        ::v-deep.g6-minimap {
            position: absolute !important;
            bottom: 20px;
            left: 20px;
            border: 1px solid #aaa;
            background-color: rgba(255, 255, 255, 0.9);
            border-radius: 4px;
        }
        ::v-deep.g6-tooltip {
            border: 1px solid #e2e2e2;
            border-radius: 4px;
            font-size: 12px;
            color: #545454;
            background-color: rgba(255, 255, 255, 0.9);
            padding: 10px 8px;
            box-shadow: rgb(174, 174, 174) 0px 0px 10px;
        }
    }
}
</style>
